package org.zoomdev.zoom.dao.impl;

import org.zoomdev.zoom.common.expression.Symbol;
import org.zoomdev.zoom.dao.DaoException;
import org.zoomdev.zoom.dao.Where;

import java.util.Collection;

public class SimpleWhere implements Where<Where> {
    private static final String AND = " AND ";
    private static final String OR = " OR ";
    protected StringBuilder where = new StringBuilder();
    protected boolean condition;
    protected StringBuilder having = new StringBuilder();

    private void whereRelation(StringBuilder where, String relation) {
        if (condition) {
            condition = false;
        } else {
            if (where.length() == 0) {
            } else {
                where.append(relation);
            }
        }

    }

    public Where like(String key, Like like, Object value) {
        return relationLike(key, like, value, AND, false);
    }

    public Where orWhere(Condition condition) {
        return orWhere(this, condition);
    }

    private Where relationLike(String key, Like like, Object value, String relation, boolean not) {
        assert (key != null);

        checkValue(key, value);
        whereRelation(where, relation);

        where.append(key);
        if (not) {
            where.append(" NOT");
        }
        where.append(" LIKE ?");
        addValue(key, like.toValue(value));
        return this;
    }

    private void addValue(String key, Object value) {

    }

    public Where orLike(String key, Like like, Object value) {
        return relationLike(key, like, value, OR, false);
    }

    private void checkValue(String key, Object value) {
        if (value == null) {
            throw new DaoException(String.format("名称为%s的字段值为null,请使用whereNull或者whereNotNull版本", key));
        }
    }

    public Where where(String key, Symbol symbol, Object value) {
        assert (key != null && symbol != null);
        return whereImpl(where, key, symbol, value, AND);
    }

    public Where where(Condition condition) {
        return where(this, condition);
    }

    public Where where(Where<?> sql, Condition condition) {
        whereRelation(where, AND);
        conditionWhere(sql, condition);
        return this;
    }

    protected Where whereImpl(StringBuilder where, String key, Symbol symbol, Object value, String relation) {
        checkValue(key, value);
        whereRelation(where, relation);
        where.append(key).append(symbol.value()).append("?");
        addValue(key, value);
        return this;
    }

    public Where where(String key, Object value) {
        return whereImpl(where, key, Symbol.EQ, value, AND);
    }

    public Where orWhere(String key, Object value) {
        return orWhere(key, Symbol.EQ, value);
    }

    public Where orWhere(Where<?> sql, Condition condition) {
        whereRelation(where, OR);
        conditionWhere(this, condition);
        return this;
    }

    void conditionWhere(Where<?> sql, Condition condition) {
        where.append("(");
        this.condition = true;
        condition.where(sql);
        if (this.condition) {
            throw new DaoException("Condition下至少需要一个条件");
        }
        where.append(")");
    }

    public Where orWhere(String key, Symbol symbol, Object value) {
        return whereImpl(where, key, symbol, value, OR);
    }

    public Where whereNull(String key) {
        return whereNull(key, AND, false);
    }

    private Where whereNull(String key, String relation, boolean not) {

        StringBuilder where = this.where;
        whereRelation(where, relation);
        where.append(key);
        where.append(" IS ");
        if (not) where.append("NOT ");
        where.append("NULL");

        return this;
    }

    public Where having(String key, Symbol symbol, Object value) {
        return whereImpl(having, key, symbol, value, AND);
    }


    public Where whereNotNull(String key) {
        return whereNull(key, AND, true);
    }

    public <E> Where whereNotIn(String key, Collection<E> values) {
        return whereIn(key, AND, true, values);
    }

    protected <E> Where whereIn(String key, String relation, boolean not, Collection<E> values) {
        StringBuilder where = this.where;
        whereRelation(where, relation);
        where.append(key);
        if (not) {
            where.append(" NOT");
        }
        where.append(" IN (");
        boolean first = true;
        for (Object object : values) {
            if (first) {
                first = false;
            } else {
                where.append(",");
            }
            where.append("?");
            this.addValue(key, object);
        }
        where.append(')');

        return this;
    }

    public <E> Where whereIn(String key, Collection<E> values) {
        return whereIn(key, AND, false, values);
    }
}
